
package com.chongchong.core.mp.base;

import com.baomidou.mybatisplus.extension.service.IService;
import com.chongchong.core.mp.object.MyRelationParam;
import com.chongchong.core.tool.api.R;

import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 基础业务接口
 *
 * @param <T>
 * @author
 */
public interface BaseService<T> extends IService<T> {

	/**
	 * 仅仅在spring boot 启动后的监听器事件中调用，缓存所有service的关联关系，加速后续的数据绑定效率。
	 */
	void loadRelationStruct();

	/**
	 * 逻辑删除
	 *
	 * @param ids id集合(逗号分隔)
	 * @return boolean
	 */
	boolean deleteLogic(@NotEmpty List<Long> ids);

	/**
	 * 根据最新对象和原有对象的数据对比，判断关联的字典数据和多对一主表数据是否都是合法数据。
	 * NOTE: BaseService中会给出返回CallResult.ok()的缺省实现。每个业务服务实现类在需要的时候可以重载该方法。
	 *
	 * @param data         数据对象。
	 * @param originalData 原有数据对象，null表示data为新增对象。
	 * @return 应答结果对象。
	 */
	R verifyRelatedData(T data, T originalData);

	/**
	 * 获取主表的查询结果，以及主表关联的字典数据和一对一从表数据，以及一对一从表的字典数据。
	 *
	 * @param id             主表主键Id。
	 * @param relationParam  实体对象数据组装的参数构建器。
	 * @return 查询结果对象。
	 */
	T getByIdWithRelation(Long id, MyRelationParam relationParam);

	/**
	 * 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param dataObject      主表实体对象。数据集成将直接作用于该对象。
	 * @param relationParam   实体对象数据组装的参数构建器。
	 * @param <K>             实体对象类型。
	 */
	<K extends T> void buildRelationForData(T dataObject, MyRelationParam relationParam);

	/**
	 * 集成所有与主表实体对象相关的关联数据对象。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param dataObject    主表实体对象。数据集成将直接作用于该对象。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param ignoreFields  该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 * @param <K>           实体对象类型。
	 */
	<K extends T> void buildRelationForData(T dataObject, MyRelationParam relationParam, Set<String> ignoreFields);

	/**
	 * 返回符合 filterField = filterValue 条件的一条数据。
	 *
	 * @param filterField 过滤的Java字段。
	 * @param filterValue 过滤的Java字段值。
	 * @return 查询后的数据对象。
	 */
	T getOne(String filterField, Object filterValue);


	/**
	 * 返回符合主键 in (idValues) 条件的所有数据。
	 *
	 * @param idValues 主键值集合。
	 * @return 检索后的数据列表。
	 */
	List<T> getInList(Set<Object> idValues);

	/**
	 * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。
	 *
	 * @param inFilterField  参与(In-list)过滤的Java字段。
	 * @param inFilterValues 参与(In-list)过滤的Java字段值集合。
	 * @return 检索后的数据列表。
	 */
	List<T> getInList(String inFilterField, Set<Object> inFilterValues);

	/**
	 * 返回符合 inFilterField in (inFilterValues) 条件的所有数据，并根据orderBy字段排序。
	 *
	 * @param inFilterField  参与(In-list)过滤的Java字段。
	 * @param inFilterValues 参与(In-list)过滤的Java字段值集合。
	 * @param orderBy        排序字段。
	 * @return 检索后的数据列表。
	 */
	List<T> getInList(String inFilterField, Set<Object> inFilterValues, String orderBy);

	/**
	 * 根据指定的显示字段列表、过滤条件字符串和分组字符串，返回聚合计算后的查询结果。(基本是内部框架使用，不建议外部接口直接使用)。
	 *
	 * @param selectFields 选择的字段列表，多个字段逗号分隔。
	 *                     NOTE: 如果数据表字段和Java对象字段名字不同，Java对象字段应该以别名的形式出现。
	 *                     如: table_column_name modelFieldName。否则无法被反射回Bean对象。
	 * @param whereClause  SQL常量形式的条件从句。
	 * @param groupBy      SQL常量形式分组字段列表，逗号分隔。
	 * @return 聚合计算后的数据结果集。
	 */
	List<Map<String, Object>> getGroupedListByCondition(String selectFields, String whereClause, String groupBy);

	/**
	 * 根据指定的显示字段列表、过滤条件字符串和排序字符串，返回查询结果。(基本是内部框架使用，不建议外部接口直接使用)。
	 *
	 * @param selectList  选择的Java字段列表。如果为空表示返回全部字段。
	 * @param filter      过滤对象。
	 * @param whereClause SQL常量形式的条件从句。
	 * @param orderBy     SQL常量形式排序字段列表，逗号分隔。
	 * @return 查询结果。
	 */
	List<T> getListByCondition(List<String> selectList, T filter, String whereClause, String orderBy);

	/**
	 * 用指定过滤条件，计算记录数量。(基本是内部框架使用，不建议外部接口直接使用)。
	 *
	 * @param whereClause SQL常量形式的条件从句。
	 * @return 返回过滤后的数据数量。
	 */
	Integer getCountByCondition(String whereClause);

	/**
	 * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList      主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam   实体对象数据组装的参数构建器。
	 */
	void buildRelationForDataList(List<T> resultList, MyRelationParam relationParam);

	/**
	 * 集成所有与主表实体对象相关的关联数据列表。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param ignoreFields  该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	void buildRelationForDataList(List<T> resultList, MyRelationParam relationParam, Set<String> ignoreFields);

	/**
	 * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询，批量导出没有分页机制，
	 * 因此在导出数据量较大的情况下，很容易给数据库的内存、CPU和IO带来较大的压力。而通过
	 * 我们的分批处理，可以极大的规避该问题的出现几率。调整batchSize的大小，也可以有效的
	 * 改善运行效率。
	 * 我们目前的处理机制是，先从主表取出所有符合条件的主表数据，这样可以避免分批处理时，
	 * 后面几批数据，因为skip过多而带来的效率问题。因为是单表过滤，不会给数据库带来过大的压力。
	 * 之后再在主表结果集数据上进行分批级联处理。
	 * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param batchSize     每批集成的记录数量。小于等于0时将不做分批处理。
	 */
	void buildRelationForDataList(List<T> resultList, MyRelationParam relationParam, int batchSize);

	/**
	 * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询，批量导出没有分页机制，
	 * 因此在导出数据量较大的情况下，很容易给数据库的内存、CPU和IO带来较大的压力。而通过
	 * 我们的分批处理，可以极大的规避该问题的出现几率。调整batchSize的大小，也可以有效的
	 * 改善运行效率。
	 * 我们目前的处理机制是，先从主表取出所有符合条件的主表数据，这样可以避免分批处理时，
	 * 后面几批数据，因为skip过多而带来的效率问题。因为是单表过滤，不会给数据库带来过大的压力。
	 * 之后再在主表结果集数据上进行分批级联处理。
	 * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。
	 * 也可以根据实际需求，单独调用该函数所包含的各个数据集成函数。
	 * NOTE: 该方法内执行的SQL将禁用数据权限过滤。
	 *
	 * @param resultList    主表实体对象列表。数据集成将直接作用于该对象列表。
	 * @param relationParam 实体对象数据组装的参数构建器。
	 * @param batchSize     每批集成的记录数量。小于等于0时将不做分批处理。
	 * @param ignoreFields  该集合中的字段，即便包含注解也不会在当前调用中进行数据组装。
	 */
	void buildRelationForDataList(
		List<T> resultList, MyRelationParam relationParam, int batchSize, Set<String> ignoreFields);

	/**
	 * 判断参数值主键集合中的所有数据，是否全部存在
	 *
	 * @param idSet  待校验的主键集合。
	 * @return 全部存在返回true，否则false。
	 */
	boolean existAllPrimaryKeys(Set<Long> idSet);

	/**
	 * 判断参数值列表中的所有数据，是否全部存在。另外，keyName字段在数据表中必须是唯一键值，否则返回结果会出现误判。
	 *
	 * @param inFilterField  待校验的数据字段，这里使用Java对象中的属性，如courseId，而不是数据字段名course_id
	 * @param inFilterValues 数据值列表。
	 * @return 全部存在返回true，否则false。
	 */
	<K> boolean existUniqueKeyList(String inFilterField, Set<K> inFilterValues);

}
